package com.group3.config;

import com.group3.exception.BusinessException;
import com.group3.utils.Result;
import com.group3.utils.ResultUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.ConversionNotSupportedException;
import org.springframework.beans.TypeMismatchException;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.validation.BindException;

import java.io.IOException;
import java.util.List;

@ResponseBody
@ControllerAdvice
public class MyControllerAdvice {

    private static final String logExceptionFormat = "Capture Exception By GlobalExceptionHandler: Code: %s Detail: %s";
    private final static Logger LOGGER = LoggerFactory.getLogger(MyControllerAdvice.class);


//    /**
//     * 处理异常
//     */
//    @ExceptionHandler(value = Exception.class)
//    @ResponseBody
//    public Result exceptionHandler(Exception exception) {
//        Result result=new Result();
//        //自定义类型异常
//        if(exception instanceof BusinessException){
//            BusinessException businessException = (BusinessException) exception;
//            result.setCode(businessException.getCode());
//            result.setMsg(businessException.getMsg());
//        }else if(exception instanceof BindException){//@valid注解抛出的异常
//            //使用StringBuilder来拼接错误信息,减少对象开销
//            StringBuilder stringBuilder = new StringBuilder();
//            //获取并拼接所有错误信息
//            BindException bindException= (BindException) exception;
//            BindingResult bindingResult = bindException.getBindingResult();
//            List<ObjectError> allErrors = bindingResult.getAllErrors();
//            for (ObjectError item : allErrors) {
//                stringBuilder.append(item.getDefaultMessage())
//                        .append(',');
//            }
//            //删除最后一个逗号
//            stringBuilder.deleteCharAt(stringBuilder.length()-1);
//            result.setCode(600);//这里自定义了600用于表示参数有误
//            result.setMsg(stringBuilder.toString());
//        }else {//其他异常
//            result.setCode(500);
//            result.setMsg(exception.getMessage());
//        }
//        return result;
//    }

    /**
    * 判断错误是否是已定义的已知错误，不是则由未知错误代替，同时记录在log中
    * @param e
    * @return
    */
    @ExceptionHandler(BusinessException.class)
    public Result BusinessException(BusinessException e){

        LOGGER.error("【系统异常】{}",e);
        return ResultUtil.error(e.getCode(),e.getMsg());
    }

    //运行时异常
    @ExceptionHandler(RuntimeException.class)
    public Result runtimeExceptionHandler(RuntimeException ex) {
        return resultFormat(992, ex);
    }

    //空指针异常
    @ExceptionHandler(NullPointerException.class)
    public Result nullPointerExceptionHandler(NullPointerException ex) {
        return resultFormat(993, ex);
    }

    //类型转换异常
    @ExceptionHandler(ClassCastException.class)
    public Result classCastExceptionHandler(ClassCastException ex) {
        return resultFormat(994, ex);
    }

    //IO异常
    @ExceptionHandler(IOException.class)
    public Result iOExceptionHandler(IOException ex) {
        return resultFormat(995, ex);
    }

    //未知方法异常
    @ExceptionHandler(NoSuchMethodException.class)
    public Result noSuchMethodExceptionHandler(NoSuchMethodException ex) {
        return resultFormat(996, ex);
    }

    //数组越界异常
    @ExceptionHandler(IndexOutOfBoundsException.class)
    public Result indexOutOfBoundsExceptionHandler(IndexOutOfBoundsException ex) {
        return resultFormat(997, ex);
    }

    //400错误
    @ExceptionHandler({HttpMessageNotReadableException.class})
    public Result requestNotReadable(HttpMessageNotReadableException ex) {
        System.out.println("400..requestNotReadable");
        return resultFormat(400, ex);
    }

    //400错误
    @ExceptionHandler({TypeMismatchException.class})
    public Result requestTypeMismatch(TypeMismatchException ex) {
        System.out.println("400..TypeMismatchException");
        return resultFormat(400, ex);
    }

    //400错误
    @ExceptionHandler({MissingServletRequestParameterException.class})
    public Result requestMissingServletRequest(MissingServletRequestParameterException ex) {
        System.out.println("400..MissingServletRequest");
        return resultFormat(400, ex);
    }

    //405错误
    @ExceptionHandler({HttpRequestMethodNotSupportedException.class})
    public Result request405(HttpRequestMethodNotSupportedException ex) {
        return resultFormat(405, ex);
    }

    //406错误
    @ExceptionHandler({HttpMediaTypeNotAcceptableException.class})
    public Result request406(HttpMediaTypeNotAcceptableException ex) {
        System.out.println("406...");
        return resultFormat(406, ex);
    }

    //500错误
    @ExceptionHandler({ConversionNotSupportedException.class, HttpMessageNotWritableException.class})
    public Result server500(RuntimeException ex) {
        System.out.println("500...");
        return resultFormat(500, ex);
    }

    //栈溢出
    @ExceptionHandler({StackOverflowError.class})
    public Result requestStackOverflow(StackOverflowError ex) {
        return resultFormat(998, ex);
    }

    //其他错误
    @ExceptionHandler({Exception.class})
    public Result exception(Exception ex) {
        return resultFormat(999, ex);
    }

    //其他错误
    @ExceptionHandler({BindException.class})
    public Result bindException(Exception ex) {

        //TODO  想要处理时间格式不对的异常，但是会把其他格式错误异常也处理，先不改？
        StringBuilder stringBuilder = new StringBuilder();
        //获取并拼接所有错误信息
        BindException bindException= (BindException) ex;
        BindingResult bindingResult = bindException.getBindingResult();
        List<ObjectError> allErrors = bindingResult.getAllErrors();
        for (ObjectError item : allErrors) {
            stringBuilder.append(item.getDefaultMessage())
                    .append(',');
        }
        //删除最后一个逗号
        stringBuilder.deleteCharAt(stringBuilder.length()-1);

//        System.out.println(ex.getMessage());

        return ResultUtil.error(990, stringBuilder.toString());
//        return ResultUtil.error(990, "参数格式不对哦");
    }

    private <T extends Throwable> Result resultFormat(Integer code, T ex) {
        ex.printStackTrace();
        LOGGER.error(String.format(logExceptionFormat, code, ex.getMessage()));
        return ResultUtil.error(code, ex.getMessage());
    }

}